home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / vol6n22.arc / PRN2FILE.ASM < prev    next >
Assembly Source File  |  1987-11-25  |  25KB  |  719 lines

  1. ;----------------------------------------------------------------------
  2. ; PRN2FILE.ASM - A resident program which redirects printer output.
  3. ; SYNTAX: PRN2FILE d:path:filename.ext [/Pn] [/Bn] [/U]
  4. ;  1)  Run PRN2FILE with the desired filename to activate it.
  5. ;  2)  Run it again with no filename to turn off redirection.
  6. ;  3)  Run it with a differant filename to change destination file.
  7. ;  4)  Use /P to designate the printer number (defaults to 1)
  8. ;  5)  Use /B to enter buffer size in K bytes (defaults to 4)
  9. ;  6)  Use /U to uninstall the program
  10. ;----------------------------------------------------------------------
  11. CSEG        SEGMENT
  12.         ASSUME    CS:CSEG,DS:NOTHING
  13.  
  14.         ORG    100H    ;Beginning for .COM programs
  15. START:        JMP INITIALIZE    ;Initialization code is at end
  16.  
  17. ;----------------------------------------------------------------------
  18. ; Data area used by this program
  19. ;----------------------------------------------------------------------
  20. COPYRIGHT    DB    "PRN2FILE 1.0 (c) 1987 Ziff Communications Co.$",1AH
  21. PROGRAMMER    DB    "Tom Kihlken"
  22. REDIRECT_MESS    DB    "LPT"
  23. PRN_NUM        DB    "1 Redirected to: $"
  24. BAD_FILENAME    DB    "Invalid filename.$"
  25. BAD_PARAM    DB    "Usage: PRN2FILE [path][filename][/Pn][/Bnn][/U]$"
  26. BAD_ALLOC    DB    "Memory Allocation Error.$"
  27. BAD_UNINSTALL    DB    "Cannot Uninstall.$"
  28. PRN_TXT        DB    "PRN$"
  29. CRLF        DB    13,10,"$"
  30. ERR_MESSAGE    DB    13,10,"*Buffer Overflow*",13,10
  31. MESS_LENGTH    EQU    $ - OFFSET ERR_MESSAGE
  32. OLDINT08    DD    ?    ;Old timer tick interrupt vector
  33. OLDINT17    DD    ?    ;Old printer output vector
  34. OLDINT21    DD    ?    ;Old dos function interrupt vector
  35. OLDINT28    DD    ?    ;Old dos waiting interrupt vector
  36. DOS_FLAG    DD    ?    ;Dos busy flag
  37. SWITCH        DB    0    ;On/off switch for redirecting printer
  38. TIMEOUT        DW    0    ;Holds timeout counter to flush buffer
  39. INSTALLED_SEG    DW    0    ;Segment location of installed copy
  40. WRITE_FLAG    DB    0    ;Indicates buffer should be written
  41. PRINTER_NUM    DW    0    ;Default to first parallel printer
  42. BUFF_POINTER    DW      0    ;Pointer to next space in buffer
  43. BUFF_SIZE    DW    4    ;Size of buffer
  44. BUFF_SEGMENT    DW    0    ;Segment address of buffer
  45. TIME_TO_WRITE    EQU    400H    ;Flush buffer when this full
  46.  
  47. ;-----------------------------------------------------------------------
  48. ; Interrupt 17 routine. (BIOS printer output)
  49. ; If output is to the selected printer and switch is on then redirect
  50. ; the character into a file.
  51. ;-----------------------------------------------------------------------
  52. NEWINT17    PROC    FAR
  53.         ASSUME    DS:NOTHING, ES:NOTHING
  54.  
  55.         CMP    DX,CS:PRINTER_NUM ;Is this the selected printer?
  56.         JNE    IGNORE        ;If not, let bios handle it
  57.         CMP    CS:SWITCH,1    ;Is redirection turned on?
  58.         JE    REDIRECT_IT    ;If on, take jump
  59. IGNORE:
  60.         JMP    CS:OLDINT17    ;Jump to the bios routine
  61. REDIRECT_IT:
  62.         STI            ;Get interrupts back on
  63.         MOV    CS:TIMEOUT,91    ;Reset timeout counter
  64.         PUSH    SI        ;Si will be used for a pointer
  65.         CMP    AH,1        ;Initializing the printer?
  66.         JE    WRITE_BUFF    ;If yes, then flush the buffer
  67.         OR    AH,AH        ;Printing a character?
  68.         JNZ    PRINT_RET    ;If not, take jump to return
  69.         MOV    SI,CS:BUFF_POINTER    ;Get pointer to the buffer
  70.         CMP    SI,CS:BUFF_SIZE    ;Is buffer filled up yet?
  71.         JE    PRINT_RET    ;If full just return.
  72.  
  73.         PUSH    DS        ;Save the data segment
  74.         MOV    DS,CS:BUFF_SEGMENT    ;Load DS with the buffer seg
  75.         MOV    DS:[SI],AL    ;Store the character in buffer
  76.         POP    DS        ;Restore data segment
  77.         INC    SI        ;And point to next position
  78.         MOV    CS:BUFF_POINTER,SI    ;Save the new pointer
  79.  
  80.         CMP    SI,TIME_TO_WRITE ;Is buffer filling up yet?
  81.         JL    PRINT_RET     ;If not, just return
  82. WRITE_BUFF:
  83.         MOV    CS:WRITE_FLAG,1    ;Signal buffer needs emptying
  84.         PUSH    DS
  85.          PUSH    BX
  86.         LDS    BX,CS:DOS_FLAG    ;Get location of dos flag
  87.         CMP    BYTE PTR [BX],0    ;Is dos busy flag set?
  88.         POP    BX
  89.         POP    DS
  90.         JNE    PRINT_RET    ;If busy, do nothing
  91.          CALL    WRITE_TO_FILE    ;This empties the buffer
  92. PRINT_RET:
  93.         POP    SI
  94.         MOV    AH,10010000B    ;Return printer status good
  95.         IRET            ;Return from interrupt
  96. NEWINT17    ENDP
  97.  
  98. ;----------------------------------------------------------------------
  99. ; New interrupt 08h (timer tick) decrement the timeout counter. Set
  100. ; the flush flag when counter reaches zero.
  101. ;----------------------------------------------------------------------
  102. NEWINT08    PROC    FAR
  103.         ASSUME    DS:NOTHING, ES:NOTHING
  104.  
  105.         PUSHF            ;Simulate an interrupt
  106.         CALL    CS:OLDINT08    ;Do normal timer routine
  107.         DEC    CS:TIMEOUT    ;Count down the flush time count
  108.         JNZ    STILL_TIME    ;Count until it gets to zero
  109.         CMP    CS:BUFF_POINTER,0 ;Anything in buffer?
  110.         JE    STILL_TIME    ;If not, just continue
  111.         MOV    CS:WRITE_FLAG,1    ;Set flush trigger
  112. STILL_TIME:
  113.         IRET            ;Return from timer interrupt
  114.  
  115. NEWINT08    ENDP
  116.  
  117. ;----------------------------------------------------------------------
  118. ; Interrupt 21 routine.  (DOS function calls) intercept function 40h
  119. ; when it writes to the printer.  Also check to see if WRITE_FLAG is
  120. ; set to one.  If it is then flush the buffer.
  121. ;----------------------------------------------------------------------
  122. NEWINT21    PROC    FAR
  123.         ASSUME    DS:NOTHING, ES:NOTHING
  124.  
  125.         PUSHF            ;Save the callers flags
  126.         CMP    CS:WRITE_FLAG,1    ;Buffer need to be written?
  127.         JNE    DONT_WRITE    ;If not, then just return
  128.         PUSH    DS
  129.          PUSH    BX
  130.         LDS    BX,CS:DOS_FLAG    ;Get location of DOS flag
  131.         CMP    BYTE PTR [BX],0    ;Is DOS busy flag set?
  132.         POP    BX
  133.         POP    DS
  134.         JNE    DONT_WRITE    ;If busy, do nothing
  135.         CALL    WRITE_TO_FILE    ;Empty the buffer now
  136. DONT_WRITE:
  137.         OR    AH,AH        ;Doing function zero?
  138.         JNE    NOT_ZERO
  139.         MOV    AX,4C00H    ;If yes, change it to 4Ch
  140. NOT_ZERO:
  141.         CMP    AH,40H        ;Writing to a device?
  142.         JNE    NOT_PRINTER    ;If not, just continue
  143.         CMP    BX,4        ;Writing to the printer handle?
  144.         JNE    NOT_PRINTER    ;If not, just continue
  145.         CMP    CS:SWITCH,1    ;Is redirection on?
  146.         JE    PRINT_IT    ;If yes, then redirect it
  147. NOT_PRINTER:
  148.         POPF            ;Recover flags from stack
  149.         CLI
  150.         JMP    CS:OLDINT21    ;Do the DOS function
  151.  
  152. ; Emulate print string function by involking INT 17h
  153.  
  154. PRINT_IT:
  155.         STI            ;Reenable interrupts
  156.         CLD            ;String moves forward
  157.  
  158.         PUSH    CX        ;Save these registers
  159.         PUSH    DX
  160.         PUSH    SI
  161.  
  162.         MOV    SI,DX        ;Get pointer to string
  163.         MOV    DX,PRINTER_NUM    ;Selected printer ID in DX
  164.         JCXZ    END_LOOP    ;Skip loop if count is zero
  165. PRINT_LOOP:
  166.         LODSB            ;Load next character from string
  167.         MOV    AH,00        ;Print character function
  168.         INT    17H        ;BIOS print
  169.         LOOP    PRINT_LOOP    ;Loop through whole string
  170. END_LOOP:
  171.         POP    SI
  172.         POP    DX
  173.         POP    CX
  174.  
  175.         MOV    AX,CX        ;All bytes were output
  176.         POPF            ;Restore the callers flags
  177.  
  178.         CLC            ;Return success status
  179.         STI            ;Reenable interrupts
  180.         RET    2        ;Return with current flags
  181.  
  182. NEWINT21    ENDP
  183.  
  184. ;----------------------------------------------------------------------
  185. ; This copies the buffer contents to a file. It should only be called
  186. ; when dos is in a reentrant condition.  All registers are preserved
  187. ;----------------------------------------------------------------------
  188. WRITE_TO_FILE    PROC    NEAR
  189.         ASSUME    DS:NOTHING, ES:NOTHING
  190.  
  191.         PUSH    AX        ;Save registers we need to use
  192.         PUSH    BX
  193.         PUSH    CX
  194.         PUSH    DX
  195.         PUSH    DS
  196.         PUSH    ES
  197.  
  198.         PUSH    CS
  199.         POP    DS        ;Set DS to code segment
  200.         ASSUME    DS:CSEG        ;Tell assembler DS is CSEG
  201.         MOV    WRITE_FLAG,0    ;Clear write request flag
  202.              MOV    AX,3524H    ;Get dos critical error vector
  203.         CALL    DOS_FUNCTION    ;Do the dos function
  204.         PUSH    BX        ;Save old vector on stack
  205.         PUSH    ES
  206.  
  207. ; Replace the dos severe error interrupt with our own routine.
  208.  
  209.         MOV    DX,OFFSET NEWINT24
  210.         MOV    AX,2524H    ;Setup to change int 24h vector
  211.         CALL    DOS_FUNCTION    ;Do the dos function
  212.  
  213. ; First try to open the file.  If dos returns with the carry flag set,
  214. ; the file didn't exist and we must create it.  Once the file is opened,
  215. ; advance the file pointer to the end of file to append.
  216.  
  217.         CMP    BUFF_POINTER,0    ;Anything in the buffer?
  218.         JE    REP_VECTOR    ;If not, no nothing
  219.         MOV    DX,OFFSET FILENAME ;Point to filename
  220.         MOV    AX,3D02H    ;Dos function to open file
  221.         CALL    DOS_FUNCTION    ;Do the dos function
  222.         JC    FILE_NOT_FOUND    ;Set if file doesn't exist.
  223.         MOV    BX,AX        ;Keep handle in BX also
  224.         XOR    CX,CX        ;Move dos file pointer to the
  225.         XOR    DX,DX        ;End of the file. this lets us
  226.         MOV    AX,4202H    ;Append this to an existing file
  227.         CALL    DOS_FUNCTION    ;Do the dos function
  228.         JC    CLOSE_FILE       ;On any error, take jump
  229.         JMP    SHORT WRITE_FILE
  230. FILE_NOT_FOUND:
  231.         CMP    AX,2        ;Was it file not found error?
  232.         JNE    REP_VECTOR    ;If not, just quit
  233.         MOV    CX,0020H    ;Attribute for new file
  234.         MOV    AH,3CH        ;Create file for writing
  235.         CALL    DOS_FUNCTION    ;Do the dos function
  236.         JC    CLOSE_FILE      ;On any error, take jump
  237.  
  238.         MOV    BX,AX        ;Save handle in BX also
  239. WRITE_FILE:     MOV    DX,0        ;Point to buffer
  240.         MOV    CX,BUFF_POINTER    ;Number of chars in buffer
  241.         MOV    AH,40H        ;Dos write to a device function
  242.         PUSH    DS
  243.         MOV    DS,BUFF_SEGMENT    ;Point to buffer segment
  244.         CALL    DOS_FUNCTION    ;Do the dos function
  245.         POP    DS
  246.         JC    CLOSE_FILE      ;On any error, take jump
  247.         CMP    CX,AX        ;Was everything written
  248.         JNE    CLOSE_FILE    ;If not, it was an error
  249.         CMP    CX,BUFF_SIZE    ;Was buffer full?
  250.         JNE    CLOSE_FILE    ;If not everything is OK
  251.  
  252.         MOV    DX,OFFSET ERR_MESSAGE ;Insert the error message
  253.         MOV    CX,MESS_LENGTH
  254.         MOV    AH,40H        ;Dos write to file function
  255.         CALL    DOS_FUNCTION    ;Do the dos function
  256. CLOSE_FILE:
  257.         MOV    AH,3EH        ;Dos function to close the file
  258.         CALL    DOS_FUNCTION    ;Do the dos function
  259. REP_VECTOR:
  260.         MOV     BUFF_POINTER,0    ;Indicate buffer is empty
  261.         POP    DS        ;Recover int 24h vector from stack
  262.         POP    DX
  263.         MOV    AX,2524H    ;Restore critical error vector
  264.         CALL    DOS_FUNCTION    ;Do the dos function
  265.         ASSUME    DS:NOTHING
  266.         POP    ES        ;Restore all registers
  267.         POP     DS
  268.         POP    DX
  269.         POP    CX
  270.         POP    BX
  271.         POP    AX
  272.         RET            ;Finished with writing to disk
  273.  
  274. WRITE_TO_FILE    ENDP
  275.  
  276. ;----------------------------------------------------------------------
  277. ; This routine emulates an INT 21 by calling the dos interrupt address
  278. ;----------------------------------------------------------------------
  279. DOS_FUNCTION    PROC    NEAR
  280.         ASSUME    DS:NOTHING, ES:NOTHING
  281.  
  282.         PUSHF            ;Save the processor flags
  283.         CLI            ;Clear interrupt enable bit
  284.         CALL    CS:OLDINT21    ;Execute the interupt procedure
  285.         STI            ;Enable further interrupts
  286.         RET            ;And return to calling routine
  287.  
  288. DOS_FUNCTION    ENDP
  289.  
  290. ;----------------------------------------------------------------------
  291. ; New interrupt 24h (critical dos error).  This interrupt is only in
  292. ; effect when writing to the disk.  It is required to suppress the
  293. ; 'Abort, Retry, Ignore' message.  All fatal disk errors are ignored.
  294. ;----------------------------------------------------------------------
  295. NEWINT24    PROC    FAR
  296.         ASSUME    DS:NOTHING, ES:NOTHING
  297.  
  298.         STI            ;Turn interrupts back on
  299.          XOR    AL,AL        ;Tells dos to ignore the error
  300.         MOV    CS:SWITCH,AL    ;Turn off logging of output
  301.         IRET            ;And return to dos
  302.  
  303. NEWINT24    ENDP
  304.  
  305. ;----------------------------------------------------------------------
  306. ; New interrupt 28h (DOS idle).  Check to see if write_flag is set to
  307. ; one. If it is, then flush the buffer
  308. ;----------------------------------------------------------------------
  309. NEWINT28    PROC    FAR
  310.         ASSUME    DS:NOTHING, ES:NOTHING
  311.  
  312.         STI
  313.         CMP    CS:WRITE_FLAG,0    ;Buffer need to be written?
  314.         JE    DO_NOTHING    ;If not, just continue
  315.         CALL    WRITE_TO_FILE    ;Empty the buffer
  316. DO_NOTHING:
  317.         JMP    CS:OLDINT28    ;Continue with old interrupt
  318.  
  319. NEWINT28    ENDP
  320.  
  321. ;----------------------------------------------------------------------
  322. ; Here is the code used to initialize prn2file.com.  First determine
  323. ; if prn2file is already installed.  If it is, just copy new parameters
  324. ; into the resident programs data area, otherwise save old vectors
  325. ; and replace with new ones.  The output buffer will later overlay
  326. ; this code to conserve memory.
  327. ;----------------------------------------------------------------------
  328.         ASSUME    CS:CSEG, DS:CSEG, ES:NOTHING
  329. INITIALIZE:
  330.         MOV    DX,OFFSET COPYRIGHT
  331.         CALL    STRING_CRLF    ;Display the string
  332.  
  333. ; Search for a previously installed copy of prn2file
  334.  
  335.         NOT    WORD PTR START    ;Modify to avoid false match
  336.         XOR    BX,BX        ;Start search at segment zero
  337.         MOV    AX,CS        ;Compare to this code segment
  338. NEXT_SEGMENT:
  339.         INC    BX        ;Look at next segment
  340.         CMP    AX,BX        ;Until reaching this code seg
  341.         MOV    ES,BX
  342.         JE    NOT_INSTALLED
  343.         MOV    SI,OFFSET START    ;Setup to compare strings
  344.         MOV    DI,SI
  345.         MOV    CX,16        ;16 bytes must match
  346.         REP    CMPSB        ;Compare DS:SI to ES:DI
  347.         OR    CX,CX
  348.         JNZ    NEXT_SEGMENT    ;If no match, try next segment
  349.         MOV    ES:SWITCH,1    ;Turn redirection on
  350.         MOV    DX,ES:PRINTER_NUM ;Retrieve old printer number
  351.         MOV    DS:PRINTER_NUM,DX ;Save it here
  352.         MOV    AH,1        ;Initialize the resident copy
  353.         INT    17H        ;To flush it's buffer
  354.         ADD    DL,31H        ;Convert printer num to ascii
  355.         MOV    PRN_NUM,DL    ;Put it into the message area
  356. NOT_INSTALLED:
  357.         MOV    INSTALLED_SEG,ES
  358.         PUSH    CS
  359.         POP    ES        ;Set ES to this segment
  360.         ASSUME    ES:CSEG
  361.         CMP    BYTE PTR DS:[0080],0 ;Anything entered?
  362.         JE    NO_PARAMS    ;If not, take jump
  363. PARSE:
  364.         MOV    AL,"/"        ;Look for a slash
  365.         CALL    LOAD_PARAMS
  366.         REPNE    SCASB        ;Scan for slashes
  367.         JCXZ    PARSE_DONE    ;Quit when no more slashes
  368.         MOV    AL,[DI]        ;Get the parameter
  369.         MOV WORD PTR [DI-1],2020H;Erase the slash and letter
  370.         OR    AL,32        ;Convert to lower case
  371.         CMP    AL,"p"        ;Is it the "p" parameter
  372.         JE    SLASH_P
  373.         CMP    AL,"b"        ;Is it the "b" parameter
  374.         JE    SLASH_B
  375.         CMP    AL,"u"        ;Is it the "u" parameter
  376.         JE    SLASH_U
  377. INVALID_PARAM:
  378.         MOV    DX,OFFSET BAD_PARAM ;Point to error message
  379.         JMP    ERR_EXIT
  380. SLASH_U:
  381.         JMP    UNINSTALL    ;Slash "u" means uninstall it
  382. SLASH_B:
  383.         MOV    BUFF_SIZE,0    ;Zero buff size for accumulator
  384. NEXT_DIGIT:
  385.         MOV    AX,BUFF_SIZE    ;Get current buff size
  386.         MOV    BL,10
  387.         MUL    BL        ;Times 10 for next digit
  388.         INC    DI        ;Point to next digit
  389.         MOV    BL,[DI]        ;And get the next one
  390.         SUB    BL,30H        ;Convert it to binary
  391.         JC    PARSE        ;If not a digit, keep parsing
  392.         CMP    BL,9
  393.         JA    PARSE        ;If not a digit, keep parsing
  394.         MOV    BYTE PTR [DI]," ";Erase character from command
  395.         XOR    BH,BH
  396.         ADD    AX,BX        ;Add in this digit
  397.         MOV    BUFF_SIZE,AX    ;And save the new total
  398.         JMP    NEXT_DIGIT
  399. SLASH_P:
  400.         INC    DI        ;Point to the printer number
  401.         MOV    AL,[DI]
  402.         MOV    BYTE PTR [DI]," ";Erase this char from command
  403.         MOV    PRN_NUM,AL    ;Put it in the message area
  404.         SUB    AL,31H        ;Convert it to printer number
  405.         XOR    AH,AH        ;Make it a word
  406.         CMP    AL,3        ;Printer id must be less than 3
  407.         JAE    INVALID_PARAM    ;If it isn't, take jump
  408.         MOV    PRINTER_NUM,AX    ;Store the parameter
  409.         JMP    PARSE        ;Look for more parameters
  410. NO_PARAMS:
  411.         MOV    DX,OFFSET REDIRECT_MESS ;Point to message
  412.         MOV    AH,9        ;Display the string of text
  413.         INT    21H        ;Using DOS display function
  414.         MOV    DX,OFFSET PRN_TXT ;Point to "PRN"
  415.         CALL    STRING_CRLF    ;Display the string
  416.         MOV    AL,0        ;Turn off redirection switch
  417.         JMP    CHECK_FOR_INSTALL
  418. PARSE_DONE:
  419.         CMP    BUFF_SIZE,1    ;Buff must be at least 1K
  420.         JB    INVALID_PARAM    ;If not, exit with error
  421.         CMP    BUFF_SIZE,64    ;Check for maximum buff size
  422.         JA    INVALID_PARAM    ;If above, exit with error
  423.         MOV    AL," "        ;Look for spaces
  424.         CALL    LOAD_PARAMS
  425.         REPE    SCASB        ;Scan for non-space character
  426.         JCXZ    NO_PARAMS    ;Any letters found?
  427.  
  428.         CMP    BYTE PTR [DI],":" ;Was a drive specified?
  429.         JNE    GET_DEF_DRIVE    ;If not, get the default drive
  430.         DEC    DI        ;Now DI points to first letter
  431.         MOV    AL,[DI]        ;Get drive letter in AL
  432.         MOV    WORD PTR [DI],2020H;Erase the drive and colon
  433.         JMP    STORE_DRIVE
  434. GET_DEF_DRIVE:
  435.         MOV    AH,19H        ;Get default drive
  436.         INT    21H
  437.         ADD    AL,65        ;Convert integer drive to ascii
  438. STORE_DRIVE:
  439.         MOV    AH,":"        ;AL has drive, AH has colon
  440.         MOV    WORD PTR FILENAME,AX ;Store drive and colon
  441.         MOV    AL,"\"        ;Look for a backslash
  442.         MOV    FILENAME+2,AL    ;Add a backslash to filename
  443.         CALL    LOAD_PARAMS
  444.         REPNE    SCASB        ;Scan for a backslash
  445.         JCXZ    GET_DEF_PATH    ;If no path, use current path
  446.         MOV    DI,OFFSET FILENAME+2 ;Location to store path
  447.         JMP    STORE_PATH
  448. GET_DEF_PATH:
  449.         MOV    DL,FILENAME    ;Selected drive letter
  450.         AND    DL,11011111B    ;Convert it to upper case
  451.         SUB    DL,64        ;Convert it to integer
  452.         MOV    SI,OFFSET FILENAME + 3 ;Put current path at SI
  453.         MOV    DI,SI        ;Save this for search later
  454.         MOV    AH,47H        ;DOS get current directory
  455.         INT    21H
  456.         JC    BAD_NAME_EXIT    ;Exit if invalid drive
  457.         MOV    AL,0        ;Look for end of path
  458.         CMP    [DI],AL        ;Was there any path?
  459.         JE    STORE_PATH    ;If not, don't scan it
  460.         MOV    CX,64        ;Maximum number of bytes in path
  461.         REPNE    SCASB        ;Scan for end of path string
  462.         MOV    BYTE PTR [DI-1],"\" ;Add the trailing backslash
  463. STORE_PATH:
  464.         PUSH    DI        ;Save location to append path
  465.         MOV    AL," "        ;Look for blank spaces
  466.         CALL    LOAD_PARAMS
  467.         REPE    SCASB        ;Scan for non-blank character
  468.         MOV    SI,DI
  469.         DEC    SI        ;This is first letter of path
  470.         POP    DI        ;Get back location to append
  471. COPY_PATH:
  472.         LODSB            ;Get next char of path
  473.         CMP    AL," "        ;Is it a blank?
  474.         JE    VERIFY_NAME    ;If yes, its the last char
  475.         CMP    AL,13        ;Is it a carriage return?
  476.         JE    VERIFY_NAME    ;If yes, its the last char
  477.         STOSB            ;Store this letter
  478.         JMP    COPY_PATH    ;Copy until end of path found
  479. VERIFY_NAME:
  480.         PUSH    DI        ;Save end of string location
  481.         MOV    BYTE PTR [DI],"$" ;Mark eos for dos display
  482.         MOV    DX,OFFSET REDIRECT_MESS ;Point to message
  483.         MOV    AH,9        ;Display the string of text
  484.         INT    21H        ;Using dos display function
  485.         MOV    DX,OFFSET FILENAME ;Point to filename for display
  486.         CALL    STRING_CRLF    ;Display the string
  487.         POP    DI
  488.         MOV    BYTE PTR [DI],0 ;Now make it an ascii string
  489.         MOV    DX,OFFSET FILENAME ;Dx points to the filename
  490.         MOV    AX,3D00H    ;Open this file for reading
  491.         INT    21H
  492.         JC    OPEN_ERR    ;Error may indicate not found
  493. CLOSE_IT:
  494.         MOV    BX,AX        ;Get the handle into BX
  495.         MOV    AH,3EH        ;Close the file
  496.         INT    21H
  497.         JMP    FILENAME_OK
  498. OPEN_ERR:
  499.         MOV    CX,0020H    ;Attribute for new file
  500.         MOV    AH,3CH        ;Create file for writing
  501.         INT    21H        ;Dos function to create file
  502.         JNC    CLOSE_IT    ;If no error, just close it
  503. BAD_NAME_EXIT:
  504.         MOV    DX,OFFSET BAD_FILENAME
  505. ERR_EXIT:
  506.         CALL    STRING_CRLF    ;Display the string
  507.         INT    20H        ;Just exit to dos
  508. FILENAME_OK:
  509.         MOV    ES,INSTALLED_SEG;Point to installed program
  510.         PUSH    DS:PRINTER_NUM    ;This moves the new printer
  511.         POP    ES:PRINTER_NUM    ;number to the resident copy
  512.         MOV    DI,OFFSET FILENAME ;Setup to copy the filename
  513.         MOV    SI,DI
  514.         MOV    CX,128        ;Copy entire file specification
  515.         REP    MOVSB        ;String move instruction
  516.         MOV    AL,1        ;Turn redirection on
  517. CHECK_FOR_INSTALL:
  518.         MOV    CX,CS
  519.         CMP    CX,INSTALLED_SEG
  520.         MOV    ES,INSTALLED_SEG
  521.         MOV    ES:SWITCH,AL    ;Store the new on/off switch
  522.         JE    INSTALL        ;If not installed yet, do it now
  523.         INT    20H        ;Otherwise terminate
  524.  
  525. ;----------------------------------------------------------------------
  526. ; This subroutine displays a string followed by a CR and LF
  527. ;----------------------------------------------------------------------
  528. STRING_CRLF    PROC    NEAR
  529.  
  530.         MOV    AH,9        ;Display the string of text
  531.         INT    21H        ;Using dos display function
  532.         MOV    DX,OFFSET CRLF    ;Now point to CR/LF characters
  533.         MOV    AH,9        ;Send the CR and LF
  534.         INT    21H
  535.         RET
  536.  
  537. STRING_CRLF    ENDP
  538.  
  539. ;----------------------------------------------------------------------
  540. ; This subroutine sets DI to the command line and CX to the byte count
  541. ;----------------------------------------------------------------------
  542. LOAD_PARAMS    PROC    NEAR
  543.  
  544.         MOV    DI,80H        ;Point to parameter area
  545.         MOV    CL,CS:[DI]    ;Get number of chars into CL
  546.         XOR    CH,CH        ;Make it a word
  547.         INC    DI        ;Point to first character
  548.         CLD            ;String search forward
  549.         RET
  550.  
  551. LOAD_PARAMS    ENDP
  552.  
  553. ;----------------------------------------------------------------------
  554. ; This code does the actual installation by storing the existing
  555. ; interrupt vectors and replacing them with the new ones.
  556. ; Then allocate memory for the buffer.  Exit and remain resident.
  557. ;----------------------------------------------------------------------
  558.         ASSUME    DS:CSEG, ES:CSEG
  559. INSTALL:
  560.         MOV    BX,OFFSET END_OF_CODE    ;Get end of resident code
  561.         ADD    BX,15
  562.         MOV    CL,4        ;Shift by 4 to divide by 16
  563.         SHR    BX,CL        ;This converts to paragraphs
  564.         MOV    AH,4AH        ;Modify memory block
  565.         INT    21H        ;Dos setblock function call
  566.         JNC    ALLOCATE_BUFFER    ;If it worked ok, then continue
  567. ALLOC_ERROR:
  568.         MOV    DX,OFFSET BAD_ALLOC ;Err message for bad allocation
  569.         JMP    ERR_EXIT    ;Display message and exit
  570. ALLOCATE_BUFFER:
  571.         MOV    BX,BUFF_SIZE    ;Buffer size in K bytes
  572.         MOV    CL,6        ;Shift by 6 to get paragraphs
  573.         SHL    BX,CL        ;Buffersize is in paragraphs
  574.         MOV    AH,48H
  575.         INT    21H        ;Dos allocate memory
  576.         JC    ALLOC_ERROR    ;If allocation error, take jump
  577.         MOV    BUFF_SEGMENT,AX    ;Save the segment for the buffer
  578.  
  579.         MOV    AX,BUFF_SIZE    ;Buffer size in K bytes
  580.         MOV    CL,10        ;Shift by 10 to get bytes
  581.         SHL    AX,CL
  582.         OR    AX,AX        ;Is buff_size=0 (64K)?
  583.         JNZ    SIZE_OK
  584.         DEC    AX        ;If yes, make it FFFFh
  585. SIZE_OK:
  586.         MOV    BUFF_SIZE,AX    ;Now buff_size is in bytes
  587.  
  588.         ASSUME    ES:NOTHING
  589.  
  590.         MOV    AH,34H        ;Get dos busy flag location
  591.         INT    21H
  592.         MOV    WORD PTR [DOS_FLAG]  ,BX ;Store flag address
  593.         MOV    WORD PTR [DOS_FLAG+2],ES
  594.  
  595.                MOV    AX,3508H    ;Get timer interrupt vector
  596.         INT    21H
  597.         MOV    WORD PTR [OLDINT08]  ,BX
  598.         MOV    WORD PTR [OLDINT08+2],ES
  599.         MOV    DX, OFFSET NEWINT08
  600.         MOV    AX, 2508H
  601.         INT    21H        ;Dos function to change vector
  602.  
  603.                MOV    AX,3517H    ;Get printer interrupt vector
  604.         INT    21H
  605.         MOV    WORD PTR [OLDINT17]  ,BX
  606.         MOV    WORD PTR [OLDINT17+2],ES
  607.         MOV    DX, OFFSET NEWINT17
  608.         MOV    AX, 2517H
  609.         INT    21H        ;Dos function to change vector
  610.  
  611.                MOV    AX,3521H    ;Get dos function vector
  612.         INT    21H
  613.         MOV    WORD PTR [OLDINT21]  ,BX
  614.         MOV    WORD PTR [OLDINT21+2],ES
  615.         MOV    DX, OFFSET NEWINT21
  616.         MOV    AX, 2521H
  617.         INT    21H        ;Dos function to change vector
  618.  
  619.                MOV    AX,3528H    ;Get dos waiting vector
  620.         INT    21H
  621.         MOV    WORD PTR [OLDINT28]  ,BX
  622.         MOV    WORD PTR [OLDINT28+2],ES
  623.         MOV    DX, OFFSET NEWINT28
  624.         MOV    AX, 2528H
  625.         INT    21H        ;Dos function to change vector
  626.  
  627. ;----------------------------------------------------------------------
  628. ; Deallocate our copy of the enviornment.  Exit using interrupt 27h
  629. ; (TSR). This leaves code and space for buffer resident.
  630. ;----------------------------------------------------------------------
  631.  
  632.         MOV    AX,DS:[002CH]    ;Get segment of enviornment
  633.         MOV    ES,AX        ;Put it into ES
  634.         MOV    AH,49H        ;Release allocated memory
  635.         INT    21H
  636.         MOV    DX,(OFFSET END_OF_CODE - OFFSET CSEG + 15)SHR 4
  637.         MOV    AX,3100H
  638.         INT    21H        ;Terminate and stay resident
  639.  
  640. ;----------------------------------------------------------------------
  641. ; This procedure removes PRN2FILE from memory by replacing the vectors
  642. ; and releasing the memory used for the code and buffer.
  643. ;----------------------------------------------------------------------
  644.         ASSUME    DS:CSEG, ES:NOTHING
  645. UNINSTALL:
  646.         MOV    AL,08H        ;Check the timer interrupt
  647.         CALL    CHECK_SEG    ;If changed, can't uninstall
  648.         JNE    CANT_UNINSTALL
  649.  
  650.         MOV    AL,17H        ;Check the printer interrupt
  651.         CALL    CHECK_SEG    ;If changed, can't uninstall
  652.         JNE    CANT_UNINSTALL
  653.  
  654.         MOV    AL,21H        ;Check dos interrupt
  655.         CALL    CHECK_SEG    ;If changed, can't uninstall
  656.         JNE    CANT_UNINSTALL
  657.  
  658.         MOV    AL,28H        ;Check dos idle interrupt
  659.         CALL    CHECK_SEG    ;If changed, can't uninstall
  660.         JNE    CANT_UNINSTALL
  661.  
  662.         MOV    ES,INSTALLED_SEG
  663.         ASSUME    DS:NOTHING, ES:NOTHING
  664.  
  665.         LDS    DX,ES:OLDINT08    ;Get original vector
  666.         MOV    AX,2508H
  667.         INT    21H        ;Dos function to change vector
  668.  
  669.         LDS    DX,ES:OLDINT17    ;Get original vector
  670.         MOV    AX,2517H
  671.         INT    21H        ;Dos function to change vector
  672.  
  673.         LDS    DX,ES:OLDINT21    ;Get original vector
  674.         MOV    AX,2521H
  675.         INT    21H        ;Dos function to change vector
  676.  
  677.         LDS    DX,ES:OLDINT28    ;Get original vector
  678.         MOV    AX,2528H
  679.         INT    21H        ;Dos function to change vector
  680.  
  681.         MOV    ES,ES:BUFF_SEGMENT;Get segment of buffer
  682.         MOV    AH,49H        ;Free its allocated memory
  683.         INT    21H
  684.         JC    RELEASE_ERR    ;If error, take jump
  685.  
  686.         MOV    ES,INSTALLED_SEG;The resident program segment
  687.         NOT    WORD PTR ES:START
  688.         MOV    AH,49H        ;Free its allocated memory
  689.         INT    21H
  690.         JC    RELEASE_ERR    ;If error, take jump
  691.         MOV    AX,4C00H
  692.         INT    21H        ;Exit to dos
  693. RELEASE_ERR:
  694.         MOV    DX,OFFSET BAD_ALLOC ;Memory allocation error
  695.         JMP    ERR_EXIT    ;Exit with error message
  696. CANT_UNINSTALL:
  697.         MOV    DX,OFFSET BAD_UNINSTALL ;Point to error message
  698.         JMP    ERR_EXIT    ;Exit with error message
  699.  
  700. ;----------------------------------------------------------------------
  701. ; This subroutine checks to see if an interrupt vector points to the
  702. ; installed program segment. Returns with ZF=1 if it does.
  703. ;----------------------------------------------------------------------
  704. CHECK_SEG    PROC    NEAR
  705.  
  706.         MOV    AH,35H        ;Get the vector
  707.         INT    21H        ;Dos function to get the vector
  708.         MOV    AX,ES
  709.         CMP    AX,INSTALLED_SEG;Is it the installed segment?
  710.         RET
  711.  
  712. CHECK_SEG    ENDP
  713. ;----------------------------------------------------------------------
  714. FILENAME    LABEL    BYTE        ;File name will go here
  715. END_OF_CODE    =    $ + 128        ;Allow 128 bytes for it
  716.  
  717. CSEG        ENDS
  718.         END    START
  719.